package com.active.fnd.arch.application.model
{

	import com.active.fnd.arch.application.event.NodeNavEvent;
	import com.active.fnd.arch.util.GlobalEventDispatcher;
	import com.active.fnd.arch.util.ManagedPM;

	import mx.core.UIComponent;
	import mx.rpc.AsyncResponder;
	import mx.rpc.events.FaultEvent;

	[Bindable]
	public class ApplicationPM extends ManagedPM
	{
		public var currentView:UIComponent;
		protected var currentPM:NodePM;
		[ArrayElementType("com.active.fnd.arch.application.model.Node")]
		protected var nodes:Array=[];

		protected var homeNode:Node;
		protected var currentNode:Node;

		//Add to support tabIndex
		public var currentTabIndex:int;

		public function ApplicationPM()
		{
			GlobalEventDispatcher.getInstance().addEventListener(NodeNavEvent.EVENT_TYPE, nodeNavEventHandler);
			initNodes();
//			selectNode(homeNode);
		}

		protected function initNodes():void
		{
			throw new Error("Method initNodes() in ApplicationPM must be overriden by child class!");
		}

		protected function addNode(name:String, pmClass:Class, viewClass:Class, tabIndex:int=0):void
		{
			var node:Node=new Node(name, pmClass, viewClass, tabIndex);
			if (nodes.length == 0)
			{
				homeNode=node;
			}
			nodes.push(node);
		}

		public function nodeNavEventHandler(event:NodeNavEvent):void
		{
			navToNodeByName(event.nodeName, event.parameter);
		}

		public function navToNodeByName(nodeName:String, parameter:Object=null):void
		{
			var destNode:Node=findNode(nodeName);
			navigateToNode(destNode, parameter);
		}

		private function findNode(nodeName:String):Node
		{
			var result:Node=null;
			for each (var node:Node in nodes)
			{
				if (node.name == nodeName)
				{
					result=node;
					break;
				}
			}
			if (result == null)
			{
				throw new Error("Cannot find node with name '" + nodeName + "'!");
			}
			return result;
		}

		private function navigateToNode(destNode:Node, parameter:Object):void
		{
			//Same node
			if (destNode == currentNode)
			{
				currentPM.enterNode(parameter, new AsyncResponder(enterSuccess, enterFail));
			}
			else if (currentNode)
			{
				currentTabIndex = destNode.tabIndex;
				currentPM.exitNode(new AsyncResponder(exitSuccess, exitFail));
				function exitSuccess(result:Object, token:Object=null):void
				{
					trace("Exit node " + currentNode.name + " success!");
					currentPM.removeFromPMContext(); //remove PM after exit success
					selectNode(destNode, parameter);
				}
				function exitFail(error:FaultEvent, token:Object=null):void
				{
					trace("Exit node " + currentNode.name + " fail!");
					currentTabIndex=currentNode.tabIndex;
				}
			}
			else
			{
				selectNode(destNode, parameter);
			}
		}

		private function selectNode(destNode:Node, parameter:Object=null):void
		{
			currentNode=destNode;
			currentPM=destNode.createPM();
			currentView=destNode.createView();
			currentTabIndex=destNode.tabIndex;
			currentPM.enterNode(parameter, new AsyncResponder(enterSuccess, enterFail));
		}

		private function enterSuccess(result:Object, token:Object=null):void
		{
			trace("Enter node " + currentNode.name + " success!");
		}

		private function enterFail(error:FaultEvent, token:Object=null):void
		{
			trace("Enter node " + currentNode.name + " fail!");
		}
	}
}